/*
 * Copyright 2013 Mounir IDRASSI  (mounir.idrassi@idrix.fr, for IDRIX)
 *
 * This file is part of SimCardManager.
 *
 * SimCardManager is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * SimCardManager is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SimCardManager.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

// MainDlg.cpp : implementation of the CMainDlg class
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"

#include "MainDlg.h"
#include "PinDlg.h"
#include "PhoneBookDlg.h"


LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   // center the dialog on the screen
   CenterWindow();

   // set icons
   HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
      IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
   SetIcon(hIcon, TRUE);
   HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME), 
      IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
   SetIcon(hIconSmall, FALSE);

   m_list.Attach(GetDlgItem(IDC_LIST));
   m_viewAdn.Attach(GetDlgItem(IDC_VIEW_ADN));
   m_viewFdn.Attach(GetDlgItem(IDC_VIEW_FDN));
   m_viewSms.Attach(GetDlgItem(IDC_VIEW_SMS));

   if (SCARD_S_SUCCESS ==  m_pcsc.Initialize() )
   {
      DWORD dwCount = m_pcsc.GetReadersCount();
      if (dwCount)
      {
         for (DWORD i=0; i < dwCount; i++)
         {
            m_list.AddString(m_pcsc[i]->GetName());
         }
         m_list.SetCurSel(0);
         GetDlgItem(IDC_CONNECT).EnableWindow();
      }
   }

   m_bConnected = false;
   m_bPinVerified = false;
   m_viewAdn.EnableWindow(FALSE);
   m_viewFdn.EnableWindow(FALSE);
   m_viewSms.EnableWindow(FALSE);

   return TRUE;
}

LRESULT CMainDlg::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   CSimpleDialog<IDD_ABOUTBOX, TRUE> dlg;
   dlg.DoModal(m_hWnd);
   return 0;
}

LRESULT CMainDlg::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   // TODO: Add validation code 
   EndDialog(wID);
   return 0;
}

LRESULT CMainDlg::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   EndDialog(wID);
   return 0;
}

LONG CMainDlg::VerifyPIN(CSimReader *pReader, CSimStatus& status)
{
   if (m_bPinVerified)
      return SCARD_S_SUCCESS;
   else
   {
      LONG lRet = SCARD_S_SUCCESS;
      while (true)
      {
         if (status.m_pin1TriesLeft == 0)
         {
            lRet = SCARD_W_CHV_BLOCKED;
            break;
         }

         CPinDlg pinDlg;
         pinDlg.m_tries = status.m_pin1TriesLeft;
         if (pinDlg.DoModal(m_hWnd) == IDOK)
         {
            lRet = pReader->VerifyCHV1(pinDlg.m_szPIN);
            if (lRet == SCARD_W_WRONG_CHV)
            {
               status.m_pin1TriesLeft--;
               if (IDNO == MessageBox(_T("Wrong PIN!\nDo you want to retry?"), _T("Wrong PIN"), MB_ICONWARNING|MB_YESNO))
               {
                  lRet = SCARD_W_CANCELLED_BY_USER;
                  break;
               }
            }
            else if (lRet == SCARD_W_CHV_BLOCKED)
            {
               status.m_pin1TriesLeft = 0;
               lRet = SCARD_W_CHV_BLOCKED;
               MessageBox(_T("Your PIN is blocked!\n"), _T("PIN Blocked"), MB_ICONERROR);
               break;
            }
            else if (lRet != SCARD_S_SUCCESS)
            {
               MessageBox(_T("An unknown error occured\n"), _T("Error"), MB_ICONERROR);
               break;
            }
            else
            {
               m_bPinVerified = true;
               m_szPIN = pinDlg.m_szPIN;
               status.m_pin1TriesLeft = 3;
               lRet = SCARD_S_SUCCESS;
               break;
            }            
         }
         else
         {
            lRet = SCARD_W_CANCELLED_BY_USER;
            break;
         }
      }

      return lRet;
   }
}

LRESULT CMainDlg::OnBnClickedConnect(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   int index = m_list.GetCurSel();
   CSimReader *pReader = m_pcsc[index];

   if (m_bConnected)
   {
      pReader->Disconnect();
      m_list.EnableWindow();
      SetDlgItemText(IDC_CONNECT, _T("Connect"));
      SetDlgItemText(IDC_ICCID, _T(""));
      SetDlgItemText(IDC_PIN1, _T(""));
      SetDlgItemText(IDC_PIN2, _T(""));
      SetDlgItemText(IDC_IMSI, _T(""));
      SetDlgItemText(IDC_ADN, _T(""));
      SetDlgItemText(IDC_FDN, _T(""));
      SetDlgItemText(IDC_SMS, _T(""));
      m_bConnected  = false;
      m_bPinVerified = false;
      m_viewAdn.EnableWindow(FALSE);
      m_viewFdn.EnableWindow(FALSE);
      m_viewSms.EnableWindow(FALSE);
      m_Fdn.Clear();
      m_Adn.Clear();
      m_SmsList.Clear();
      m_szPIN = _T("");
   }
   else
   {
      if (!pReader->IsCardPresent())
         MessageBox(_T("No card present on the selected reader"), _T("Empty reader"), MB_ICONWARNING);
      else
      {
         CWaitCursor wait;
         TCHAR szDesc[512];
         LONG lRet = pReader->Connect();
         if (lRet == SCARD_E_PROTO_MISMATCH)
            MessageBox(_T("The card doesn't support T=0 protocol. We can't continue!"), _T("Insupported Protocol"), MB_ICONWARNING);
         else if (SCARD_S_SUCCESS != lRet)
         {
            _stprintf(szDesc, _T("Error (0x%.8X) occured while connecting to the card"), lRet);
            MessageBox(szDesc, _T("PC/SC Error"), MB_ICONERROR);
         }
         else
         {
            BYTE pbData[256];            
            DWORD dwLen;
            CSimStatus status;
            ByteArray FCI;

            pReader->BeginTransaction();

            LONG lRet = pReader->Select(0x3F00);
            if (lRet == SCARD_S_SUCCESS)
            {
               if (pReader->GetStatus(status))
               {
                  lRet = pReader->Select(0x2FE2); // EF ICCD ID
                  if (lRet == SCARD_S_SUCCESS)
                  {
                     lRet = pReader->ReadBinary(0x0A, pbData);
                     if (lRet == SCARD_S_SUCCESS)
                     {
                        dwLen = 0x0A;
                        std::string szICCID = FromBCD(pbData, dwLen);
                        SetDlgItemTextA(m_hWnd, IDC_ICCID, szICCID.c_str());                  

                        lRet = pReader->Select(0x7F20); // DF GSM
                        if (lRet == SCARD_S_SUCCESS)
                        {
                           lRet = pReader->Select(0x6F07, FCI); // EF IMSI
                           if (lRet == SCARD_S_SUCCESS)
                           {
                              SimACL readAC, updateAC;
                              unsigned short uSize;

                              lRet = pReader->GetEfInfo(FCI, uSize, readAC, updateAC);
                              if (lRet == SCARD_S_SUCCESS)
                              {
                                 // verify PIN if it is enabled
                                 if (status.m_bPin1Enabled && (readAC == AC_CHV1))
                                 {
                                    if (status.m_pin1TriesLeft == 0)
                                    {
                                       MessageBox(_T("Your PIN is blocked!\nIMSI file can't be read."), _T("PIN Blocked"), MB_ICONERROR);
                                    }
                                    else
                                    {
                                       lRet = VerifyPIN(pReader, status);
                                       if (lRet == SCARD_W_CANCELLED_BY_USER)
                                          MessageBox(_T("No PIN entered.\n We can't read the IMSI EF without it"), _T("PIN Needed"), MB_ICONWARNING);
                                    }    
                                 }

                                 lRet = pReader->ReadBinary((BYTE) uSize, pbData);
                                 if (lRet == SCARD_S_SUCCESS)
                                 {
                                    dwLen = uSize - 1;
                                    std::string szIMSI = FromBCD(&pbData[1], dwLen);
                                    SetDlgItemTextA(m_hWnd, IDC_IMSI, szIMSI.c_str() + 1);
                                 }
                                 else
                                 {
                                    SetDlgItemText(IDC_IMSI, _T("Failed to read IMSI file"));
                                 }
                              }
                           }                           
                        }

                        CWaitCursor wait;
                        CSimStatus newStatus;
                        if (pReader->GetStatus(newStatus))
                        {
                           status.m_bPin1Enabled = newStatus.m_bPin1Enabled;
                           status.m_bPin2Enabled = newStatus.m_bPin2Enabled;
                           status.m_pin1TriesLeft = newStatus.m_pin1TriesLeft;
                           status.m_pin2TriesLeft = newStatus.m_pin2TriesLeft;
                        }

                        if (status.m_bPin1Enabled)
                           _stprintf(szDesc, _T("Enabled and %d tries left."), status.m_pin1TriesLeft);
                        else
                           _stprintf(szDesc, _T("Disabled"));
                        SetDlgItemText(IDC_PIN1, szDesc);
                        if (status.m_bPin2Enabled)
                           _stprintf(szDesc, _T("Enabled and %d tries left."), status.m_pin2TriesLeft);
                        else
                           _stprintf(szDesc, _T("Disabled"));
                        SetDlgItemText(IDC_PIN2, szDesc);   

                        // Read phone books
                        lRet = pReader->Select(0x3F00);
                        if (lRet == SCARD_S_SUCCESS)
                        {
                           lRet = pReader->Select(0x7F10); // DF TELECOM
                           if (lRet == SCARD_S_SUCCESS)
                           {
                              lRet = pReader->Select(0x6F3B, FCI); // EF FDN
                              if (lRet == SCARD_S_SUCCESS)
                              {
                                 SimACL readAC, updateAC;
                                 unsigned short uSize;

                                 lRet = pReader->GetEfInfo(FCI, uSize, readAC, updateAC);
                                 if (lRet == SCARD_S_SUCCESS)
                                 {
                                    lRet = pReader->GetPhoneBookInfo(FCI, m_Fdn);
                                    if ((lRet == SCARD_S_SUCCESS) && m_Fdn.m_bEnabled)
                                    {
                                       // verify PIN if it is enabled
                                       if (status.m_bPin1Enabled && (readAC == AC_CHV1) && !m_bPinVerified)
                                       {
                                          if (status.m_pin1TriesLeft == 0)
                                          {
                                             MessageBox(_T("Your PIN is blocked!\nFDN file can't be read."), _T("PIN Blocked"), MB_ICONERROR);
                                          }
                                          else
                                          {
                                             lRet = VerifyPIN(pReader, status);
                                             if (lRet == SCARD_W_CANCELLED_BY_USER)
                                                MessageBox(_T("No PIN entered.\n We can't read the FDN EF without it"), _T("PIN Needed"), MB_ICONWARNING);
                                          }    
                                       }

                                       lRet = pReader->ReadPhoneBook(m_Fdn);
                                    }
                                 }
                              }

                              lRet = pReader->Select(0x6F3A, FCI); // EF ADN
                              if (lRet == SCARD_S_SUCCESS)
                              {
                                 SimACL readAC, updateAC;
                                 unsigned short uSize;

                                 lRet = pReader->GetEfInfo(FCI, uSize, readAC, updateAC);
                                 if (lRet == SCARD_S_SUCCESS)
                                 {
                                    lRet = pReader->GetPhoneBookInfo(FCI, m_Adn);
                                    if ((lRet == SCARD_S_SUCCESS) && m_Adn.m_bEnabled)
                                    {
                                       // verify PIN if it is enabled
                                       if (status.m_bPin1Enabled && (readAC == AC_CHV1) && !m_bPinVerified)
                                       {
                                          if (status.m_pin1TriesLeft == 0)
                                          {
                                             MessageBox(_T("Your PIN is blocked!\nADN file can't be read."), _T("PIN Blocked"), MB_ICONERROR);
                                          }
                                          else
                                          {
                                             lRet = VerifyPIN(pReader, status);
                                             if (lRet == SCARD_W_CANCELLED_BY_USER)
                                                MessageBox(_T("No PIN entered.\n We can't read the ADN EF without it"), _T("PIN Needed"), MB_ICONWARNING);
                                          }    
                                       }

                                       lRet = pReader->ReadPhoneBook(m_Adn);
                                    }
                                 }
                              }

                              lRet = pReader->Select(0x6F3C, FCI); // EF SMS
                              if (lRet == SCARD_S_SUCCESS)
                              {
                                 SimACL readAC, updateAC;
                                 unsigned short uSize;

                                 lRet = pReader->GetEfInfo(FCI, uSize, readAC, updateAC);
                                 if (lRet == SCARD_S_SUCCESS)
                                 {
                                    lRet = pReader->GetSmsInfo(FCI, m_SmsList);
                                    if (lRet == SCARD_S_SUCCESS)
                                    {
                                       // verify PIN if it is enabled
                                       if (status.m_bPin1Enabled && (readAC == AC_CHV1) && !m_bPinVerified)
                                       {
                                          if (status.m_pin1TriesLeft == 0)
                                          {
                                             MessageBox(_T("Your PIN is blocked!\nSMS records file can't be read."), _T("PIN Blocked"), MB_ICONERROR);
                                          }
                                          else
                                          {
                                             lRet = VerifyPIN(pReader, status);
                                             if (lRet == SCARD_W_CANCELLED_BY_USER)
                                                MessageBox(_T("No PIN entered.\n We can't read the SMS records without it"), _T("PIN Needed"), MB_ICONWARNING);
                                          }    
                                       }

                                       lRet = pReader->ReadSms(m_SmsList);
                                    }
                                 }
                              }


                           }
                        }

                        if (m_Adn.m_bEnabled)
                        {
                           if (m_Adn.m_list.size())
                              m_viewAdn.EnableWindow(TRUE);
                           _stprintf(szDesc, _T("Enabled with %d entries"), m_Adn.m_list.size());
                        }
                        else
                           _stprintf(szDesc, _T("Disabled"));
                        SetDlgItemText(IDC_ADN, szDesc);   

                        if (m_Fdn.m_bEnabled)
                        {
                           if (m_Fdn.m_list.size())
                              m_viewFdn.EnableWindow(TRUE);
                           _stprintf(szDesc, _T("Enabled with %d entries"), m_Fdn.m_list.size());
                        }
                        else
                           _stprintf(szDesc, _T("Disabled"));
                        SetDlgItemText(IDC_FDN, szDesc); 

                        _stprintf(szDesc, _T("%d messages"), (int) m_SmsList.m_list.size());
                        SetDlgItemText(IDC_SMS, szDesc);

                        if (!m_SmsList.m_list.empty())
                           m_viewSms.EnableWindow(TRUE);

                        m_bConnected = true;
                     }
                  }
               }
            }

            pReader->EndTransaction();

            if (!m_bConnected)
            {
               MessageBox(_T("The card is not a GSM SIM card"), _T("Incompatible card"), MB_ICONWARNING);
               pReader->Disconnect();
            }
            else
            {
               m_list.EnableWindow(FALSE);
               SetDlgItemText(IDC_CONNECT, _T("Disconnect"));
            }
         }
      }
   }

   return 0;
}

LRESULT CMainDlg::OnNMClickSyslink1(int /*idCtrl*/, LPNMHDR pNMHDR, BOOL& /*bHandled*/)
{
   ShellExecute(m_hWnd, _T("open"), _T("http://www.idrix.fr"),NULL,NULL,SW_NORMAL);
   return 0;
}

LRESULT CMainDlg::OnBnClickedViewAdn(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{

   CPhoneBookDlg dlg(m_Adn, CPhoneBookDlg::ADN_DLG);
   dlg.DoModal();

   return 0;
}

LRESULT CMainDlg::OnBnClickedViewFdn(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   CPhoneBookDlg dlg(m_Fdn, CPhoneBookDlg::FDN_DLG);
   dlg.DoModal();

   return 0;
}

LRESULT CMainDlg::OnBnClickedViewSms(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
   CPhoneBookDlg dlg(m_SmsList);
   dlg.DoModal();   
   return 0;
}
